package ro.ubbcluj.cs.damate.plugin.monitors;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IExecutionListener;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;

import ro.ubbcluj.cs.damate.plugin.events.CommandEvent;
import ro.ubbcluj.cs.damate.plugin.services.DamateMonitoringService;
import static ro.ubbcluj.cs.damate.plugin.utils.PluginEventConstants.*;

/**
 * Instances of this class monitor invocations of commands in the workbench.
 * 
 */
public class CommandUsageMonitor implements EventMonitor {
	private static final String COMMANDS_EXTENSION_POINT = "org.eclipse.ui.commands"; //$NON-NLS-1$

	/**
	 * The {@link #executionListener} is installed into the {@link ICommandService}
	 * so that it can be notified when a command is invoked.
	 */
	private IExecutionListener executionListener;
	
	private ExtensionIdToBundleMapper commandToBundleIdMapper;
		
	public void startMonitoring(final DamateMonitoringService monitoringService) {		
		this.executionListener = new IExecutionListener() {
			public void notHandled(String commandId, NotHandledException exception) {
				recordEvent(NO_HANDLER, monitoringService, commandId);
			}

			public void postExecuteFailure(String commandId, ExecutionException exception) {
				recordEvent(FAILED, monitoringService, commandId);				
			}

			public void postExecuteSuccess(String commandId, Object returnValue) {
				recordEvent(EXECUTED, monitoringService, commandId);
			}

			public void preExecute(String commandId, ExecutionEvent event) {
				
			}			
		};
		getCommandService().addExecutionListener(executionListener);
		commandToBundleIdMapper = new ExtensionIdToBundleMapper(COMMANDS_EXTENSION_POINT);
	}

	private ICommandService getCommandService() {
		return (ICommandService) PlatformUI.getWorkbench().getAdapter(ICommandService.class);
	}
	
	public void stopMonitoring() {
		ICommandService commandService = getCommandService();
		if (commandService != null) commandService.removeExecutionListener(executionListener);
		commandToBundleIdMapper.dispose();
	}

	private void recordEvent(String what, final DamateMonitoringService monitoringService, String commandId) {
		CommandEvent event = new CommandEvent();
		event.setKind(COMMAND);
		event.setWhat(what);
        event.addParameter(WORKSPACE, ResourcesPlugin.getWorkspace().getRoot().getLocation().toString());
		event.addParameter(COMMAND_ID, commandId);
		monitoringService.recordEvent(event, getBundleId(commandId), null);
	}
	
	/**
	 * This method fetches the bundle id (symbolic name) of the bundle that defines
	 * the command, commandId. 
	 * 
	 * @param commandId
	 * @return
	 */
	protected synchronized String getBundleId(String commandId) {
		return commandToBundleIdMapper.getBundleId(commandId);
	}
}
